<?php

class vk implements ISingleton
{

	private $_app_id = '';

	private $_secret_key = '';

	private $_current_user_id = 0;

	private $_access_token = null;

	private $_user = array();

	private $_vkUser;

	private $_strParams = '';

	private $_strResponse = '';

	private static $_instance = null;

	public static function getInstance()
	{
		if (! self::$_instance) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}

	/**
	 * Получает объект текущего авторизованного пользователя, либо null.
	 *
	 * @return VkUser
	 */
	public function getUser()
	{
		if ($this->_vkUser) {
			return $this->_vkUser;
		}
		
		return $this->_getUserByAvailableInformation();
	}

	/**
	 * Получает объект текущего пользователя, используя параметр $_GET['code']
	 *
	 * @return VkUser null
	 * @throws Zend_Auth_Exception
	 */
	protected function _getUserByAvailableInformation()
	{
		if (! isset($_GET['code'])) {
			return null;
		}
		
		$query = 'https://api.vk.com/oauth/access_token?client_id=' .
				 $this->_app_id . '&client_secret=' . $this->_secret_key .
				 '&code=' . $_GET['code'];
		$uri = Zend_Uri::factory($query);
		$client = new Zend_Http_Client($uri);
		$result = $client->request();
		$response = json_decode($result->getBody(), true);
		if (isset($response['error'])) {
			throw new Zend_Auth_Exception($response['error_description']);
		}
		$this->_vkUser = new VkUser($response['user_id']);
		return $this->_vkUser;
	}

	public function __construct()
	{
		$config = Config::getInstance();
		$this->_app_id = $config->vk->app_id;
		$this->_secret_key = $config->vk->app_secret;
	}

	public function getAppId()
	{
		return $this->_app_id;
	}

	public function getSecretKey()
	{
		return $this->_secret_key;
	}

	public function getCurrentUserId()
	{
		if (empty($this->_user)) {
			$this->isAuth();
		}
		return $this->_user['id'];
	}

	public function getAccessToken()
	{
		if (empty($this->_user)) {
			$this->isAuth();
		}
		if (! empty($this->_user['access_token'])) {
			return $this->_access_token;
		} else {
			return null;
		}
	}

	/**
	 *
	 * @param string $method        	
	 * @param array $params        	
	 * @return array
	 * @throws Zend_Service_Exception
	 */
	public function api($method, $params = array())
	{
		$pice = array();
		foreach ($params as $k => $v) {
			$pice[] = $k . '=' . urlencode($v);
		}
		$params = implode('&', $pice);
		$this->_strParams = $params;
		$url = 'https://api.vk.com/method/' . $method . '?' . $params;
		$client = new Zend_Http_Client($url);
		$result = $client->request();
		$response = json_decode($result->getBody(), true);
		$this->_strResponse = $result->getBody();
		if (isset($response['error'])) {
			if ($response['error']['error_code'] == 14) {
				// если включен antigate
				if (Config::getInstance()->vk->antigate->enabled == 1) {
					// скачиваем vk капчу
					$captchaFile = '_vkCaptcha_' . md5($response['captcha_img']) .
							 '.jpg';
					$captchaUpload = file_put_contents('tmp/' . $captchaFile, 
							$response['captcha_img']);
					if ($captchaUpload == false) {
						throw new Zend_Service_Exception(
								'Не удалось скачать VK капчу ' .
										 $response['captcha_img']);
					}
					$captchaPath = realpath($captchaFile);
					if (! is_file($captchaPath)) {
						throw new Zend_Service_Exception(
								'Не найден скаченный файл VK капчи ' .
										 $captchaPath);
					}
					// определяем post данные
					$data = array(
							'key' => Config::getInstance()->vk->antigate->apikey,
							'file' => '@' . $captchaPath,
							'phrase' => 0,
							'regsense' => 0,
							'numeric' => 0,
							'min_len' => 3,
							'max_len' => 5
					);
					$agClient = new Zend_Http_Client();
					$agClient->setAdapter('Zend_Http_Client_Adapter_Curl');
					$agClient->setUri(
							Zend_Uri::factory('http://antigate.com/in.php'));
					$agClient->setParameterPost($data);
					$agClient->setConfig(
							array(
									'timeout' => 60
							));
					$_result = $agClient->request('POST');
					$_response = $_result->getBody();
					if (strpos($_response, "ERROR") !== false) {
						throw new Zend_Service_Error(
								'Server antigate.com returned error: ' .
										 $_response);
					}
					
					$exp = explode('|', $_response);
					$captcha_id = $exp[1];
					$waittime = 0;
					sleep(2);
					while (true) {
						$result = file_get_contents(
								"http://antigate.com/res.php?key=" . $data['key'] .
										 '&action=get&id=' . $captcha_id);
						if (strpos($result, 'ERROR') !== false) {
							throw new Zend_Service_Error(
									'Server antigate.com returned error: ' .
											 $result);
						}
						if ($result == "CAPCHA_NOT_READY") {
							$waittime += 2;
							if ($waittime > 120) {
								break;
							}
							sleep(2);
						} else {
							$ex = explode('|', $result);
							if (trim($ex[0]) == 'OK') {
								return array(
										'captcha_sid' => $response['captcha_sid'],
										'captcha_key' => trim($ex[1])
								);
							}
						}
					}
					throw new Zend_Service_Exception(
							'Не удалось распознать VK капчу');
				}
				// иначе показываем капчу
				return $response['error'];
			}
			throw new Zend_Service_Exception($response['error']['error_msg']);
		}
		return $response['response'];
	}

	public function getStrParams()
	{
		return $this->_strParams;
	}

	public function getStrResponse()
	{
		return $this->_strResponse;
	}

	public function uploadWallPhoto($upload_url, $photo_url)
	{
		$client = new Zend_Http_Client();
		// указываем url, куда обращаться, куда загружаем изображение
		$client->setUri($upload_url);
		// определяем метод запроса
		$client->setMethod(Zend_Http_Client::POST);
		// указываем файл изображения
		$client->setFileUpload($photo_url, 'photo');
		// выполняем запрос
		$result = $client->request();
		// смотрим результаты (сразу приходят в json)
		if ($result->isError()) {
			return $result->getStatus();
		} else {
			return Zend_Json::decode($result->getBody());
			// таким образом мы получили строку вида
			// {"mid": "1111111", "gid": "0", "server": "11111",
			// "photo": "837556e9f8x", "hash":
			// "e72597b6a5c86589e02c933458dc8e4c"}
		}
	}

	/**
	 * Проеверка cookie vk
	 *
	 * @return array
	 */
	public function isAuth()
	{
		$session = array();
		$member = FALSE;
		$valid_keys = array(
				'expire',
				'mid',
				'secret',
				'sid',
				'sig'
		);
		$app_cookie = (isset($_COOKIE['vk_app_' . $this->_app_id])) ? $_COOKIE['vk_app_' .
				 $this->_app_id] : false;
		if ($app_cookie) {
			$session_data = explode('&', $app_cookie, 10);
			
			foreach ($session_data as $pair) {
				list ($key, $value) = explode('=', $pair, 2);
				if (empty($key) || empty($value) || ! in_array($key, 
						$valid_keys)) {
					continue;
				}
				$session[$key] = $value;
			}
			foreach ($valid_keys as $key) {
				if (! isset($session[$key]))
					return $member;
			}
			ksort($session);
			
			$sign = '';
			foreach ($session as $key => $value) {
				if ($key != 'sig') {
					$sign .= ($key . '=' . $value);
				}
			}
			$sign .= $this->_secret_key;
			$sign = md5($sign);
			
			if ($session['sig'] == $sign /*&& $session['expire'] > time()*/) {
				$this->_user = UserPeer::getInstance()->getUserInfo(
						$session['mid']);
				return $this->_user;
			}
		}
		return array();
	}

	public function getUserInfo()
	{
		if (! $this->_currentUserId) {
			$this->isAuth();
		}
		$select = UserPeer::getInstance()->select()->where('vk_id = ?', 
				$this->_currentUserId);
		$row = UserPeer::getInstance()->fetchRow($select);
		if ($row) {
			return $row->toArray();
		}
		return false;
	}
}